﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using RuYiAdmin.Net.Common.Global;
using RuYiAdmin.Net.Common.Utility;
using RuYiAdmin.Net.Entity.BusinessDTO.SystemManagement;
using RuYiAdmin.Net.Entity.BusinessEntity.SystemManagement;
using RuYiAdmin.Net.Entity.BusinessEnum;
using RuYiAdmin.Net.Repository.Base;
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace RuYiAdmin.Net.WebApi.AppCode.ActionFilters
{
    /// <summary>
    /// 审计日志过滤器
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class LogAttribute : ActionFilterAttribute
    {
        private OperationType operationType { get; set; }

        public LogAttribute(OperationType operationType)
        {
            this.operationType = operationType;
        }

        public override void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);

            //设置审计日志开关
            if (!GlobalContext.LogConfig.IsEnabled)
            {
                return;
            }

            var token = context.HttpContext.GetToken();
            //获取用户
            var user = RedisUtil.Get<SysUserDTO>(token);
            if (user == null)
            {
                throw new Exception("token is not valid");
            }

            #region 监控信息入库

            var log = new SysLog();

            log.Id = Guid.NewGuid();
            log.UserId = user.Id;
            log.UserName = user.DisplayName;

            log.OrgId = user.OrgId;
            if (log.OrgId.Equals(Guid.Empty))
            {
                log.OrgName = "none";
            }
            else
            {
                log.OrgName = user.OrgName;
            }

            log.System = context.HttpContext.Request.Headers["User-Agent"].FirstOrDefault().ToString().Split('(')[1].Split(')')[0];
            log.Browser = context.HttpContext.Request.Headers["sec-ch-ua"];

            var ip = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.HttpContext.Connection.RemoteIpAddress.ToString();
            }
            log.IP = ip;

            log.OperationType = this.operationType;
            log.RequestUrl = context.HttpContext.Request.Path.Value;

            #region 设置参数

            switch (context.HttpContext.Request.Method)
            {
                case "GET":
                case "DELETE":
                    log.Params = context.HttpContext.Request.Path;
                    break;
                case "PUT":
                case "POST":
                    context.HttpContext.Request.EnableBuffering();
                    context.HttpContext.Request.Body.Position = 0;
                    StreamReader reader = new StreamReader(context.HttpContext.Request.Body, Encoding.UTF8);
                    log.Params = reader.ReadToEndAsync().GetAwaiter().GetResult();
                    context.HttpContext.Request.Body.Position = 0;
                    break;
                default: break;
            }
            if (log.Params != null && log.Params.Length > 1024)
            {
                log.Params = log.Params.Substring(0, 1021) + "...";
            }
            #endregion

            #region 设置返回值

            var isFileStream = context.Result.GetType().Equals(typeof(Microsoft.AspNetCore.Mvc.FileStreamResult));
            var isFile = context.Result.GetType().Equals(typeof(Microsoft.AspNetCore.Mvc.FileResult));
            if (!isFileStream && !isFile)
            {
                var result = JsonConvert.SerializeObject(((Microsoft.AspNetCore.Mvc.ObjectResult)context.Result).Value);
                if (result != null)
                {
                    if (result.Length > 2000)
                    {
                        log.Result = result.Substring(0, 2000) + "...";

                        //返回结果落盘
                        var monitoringLogsPath = String.Join(String.Empty, GlobalContext.DirectoryConfig.GetMonitoringLogsPath(), "/" + log.Id + ".txt");
                        var file = new FileStream(monitoringLogsPath, FileMode.Create);
                        byte[] byteArray = System.Text.Encoding.Default.GetBytes(result);
                        file.Write(byteArray, 0, byteArray.Length);
                        file.Flush();
                        file.Close();
                    }
                    else
                    {
                        log.Result = result;
                    }
                }
            }

            #endregion

            log.OldVaue = String.Empty;
            log.NewValue = String.Empty;
            log.Remark = $"{user.DisplayName}于{DateTime.Now}访问了{log.RequestUrl}接口";

            log.IsDel = 0;
            log.Creator = user.Id;
            log.CreateTime = DateTime.Now;
            log.Modifier = user.Id;
            log.ModifyTime = DateTime.Now;

            SqlSugarDbContext.Repository.Insertable<SysLog>(log).ExecuteCommand();

            #endregion
        }
    }
}
